package com.program.houai.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.program.houai.entity.*;
import com.program.houai.enums.UserTypeEnum;
import com.program.houai.exception.BusinessException;
import com.program.houai.exception.ErrorType;
import com.program.houai.mapper.UserMapper;
import com.program.houai.po.WxUserDTO;
import com.program.houai.service.*;
import com.program.houai.util.BASE64Utils;
import com.program.houai.util.DateFullUtils;
import com.program.houai.util.R;
import com.program.houai.util.SystemConstant;
import com.program.houai.vo.H5UserVO;
import com.program.houai.vo.UserOrderVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import com.program.houai.po.WxLoginResponse;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import org.apache.commons.lang3.RandomStringUtils;

/**
 * @author liyinsong
 * @date 2022/2/28 16:12
 */
@Service
@Slf4j
public class UserServiceImpl  extends ServiceImpl<UserMapper, UserEntity> implements IUserService {

    @Value("${vx.appId}")
    private String appId;

    private String appSecret;

    @Value("${login.system.salt}")
    private String systemSalt;

    @Autowired
    private IWxUserService wxUserService;

    @Autowired
    private IUserVipCardService userVipCardService;

    @Autowired
    private IChildUserVipCardService childUserVipCardService;

    @Autowired
    private IMemberCardService memberCardService;

    @Autowired
    private IAppMemberService appMemberService;

    @Value("${system.file.request-url}")
    private String requestUrl;

    @Value(("${vx.secret}"))
    public void setAppSecret(String appSecret){
        this.appSecret = appSecret;
    }
    @Autowired
    private RestTemplate restTemplate;
    @Override
    public R<Object> wxLogin(String code) {

        //发送appid+appsecret+code到wx服务器
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(SystemConstant.WX_LOGIN_AUTH_URL,
                String.class, appId, appSecret, code);

        WxLoginResponse wxLoginResponse = JSON.parseObject(responseEntity.getBody(), WxLoginResponse.class);
        if (StringUtils.hasText(wxLoginResponse.getErrcode())) {
            log.error("wx login failed, errmsg is [{}]", wxLoginResponse.getErrmsg());
            return R.failed("登录失败");
        }

        return R.ok(wxLoginResponse,"登录成功");
    }

    @Override
    public UserEntity selectUserByUsername(String username) {
        QueryWrapper<UserEntity> wrap = new QueryWrapper<UserEntity>();
        wrap.eq("username",username);
        UserEntity user = this.getOne(wrap);
        return user;
    }

    @Override
    public UserEntity selectUserByOpenId(String openId) {
        QueryWrapper<UserEntity> wrap = new QueryWrapper<UserEntity>();
        wrap.eq("open_id",openId);
        UserEntity user = this.getOne(wrap);
        return user;
    }

    @Override
    public boolean checkWxUser(String rawData, String signature, String sessionKey) {
        String data = rawData + sessionKey;
        //用sha1算法计算出密文
        String sign = DigestUtils.sha1Hex(data);

        return sign.equals(signature);
    }

    @Override
    public WxUserDTO decryptWxUserInfo(String encryptedData, String iv, String sessionKey) throws Exception {
        String decrypt = decrypt(encryptedData, iv, sessionKey);

        return JSONObject.parseObject(decrypt, WxUserDTO.class);
    }

    @Override
    public int registryWxUserInfo(WxUserDTO wxUserDTO) {
        QueryWrapper<WxUserEntity> wrap = new QueryWrapper<WxUserEntity>();
        wrap.eq("open_id",wxUserDTO.getOpenId());
        WxUserEntity findUser = wxUserService.getOne(wrap);
        //已有该用户
        if (Objects.nonNull(findUser)) {
            //更新
            BeanUtils.copyProperties(wxUserDTO, findUser);
            findUser.setUpdateTime(new Date());
            wxUserService.getBaseMapper().updateById(findUser);
            log.info("update wx user[{}] success", findUser.getOpenId());
        } else {
            String username = RandomStringUtils.randomNumeric(11);
            //插入
            WxUserEntity userEntity = new WxUserEntity();
            BeanUtils.copyProperties(wxUserDTO, userEntity);
            userEntity.setCreateTime(new Date());
            wxUserService.save(userEntity);
            log.info("insert 微信usersuccess.");
        }

        return 1;
    }

    @Transactional
    @Override
    public boolean registryUserInfo(UserEntity userEntity) {
        QueryWrapper<UserEntity> wrap = new QueryWrapper<UserEntity>();
        wrap.eq("phone",userEntity.getPhone());
        UserEntity findUser = this.getOne(wrap);
        if (findUser != null){
            throw new BusinessException(ErrorType.BIZ_ERROR,"该手机号码已注册");
        }
        userEntity.setType(UserTypeEnum.WX_USER.getCode());
        String password = userEntity.getPhone().substring(userEntity.getPhone().length()-4,userEntity.getPhone().length());
        String bcryptPassword = BASE64Utils.bcryptPassword(password);
        userEntity.setPassword(bcryptPassword);
        boolean result = this.save(userEntity);
        log.info("insert 用户数据成功");
        //更改 wxUser表数据
        QueryWrapper<WxUserEntity> wxUserWrap = new QueryWrapper<WxUserEntity>();
        wxUserWrap.eq("open_id",userEntity.getOpenId());
        WxUserEntity wxUser = wxUserService.getOne(wxUserWrap);
        //已有该用户
        if (Objects.nonNull(wxUser)) {
            //更新
            wxUser.setUpdateTime(new Date());
            wxUser.setGender(userEntity.getGender());
            wxUser.setAvatarUrl(userEntity.getAvatarUrl());
            wxUser.setPhone(userEntity.getPhone());
            wxUserService.getBaseMapper().updateById(wxUser);
            log.info("update wxuser[{}] success", userEntity.getPhone());
        }
        return result;
    }

    @Override
    public IPage<UserOrderVO> getAllOrderList(IPage page, List<Integer> userIdList,  Integer txnStatus,String isRoyalty,String startTime,String endTime) {
        return this.getBaseMapper().getAllOrderList(page,userIdList,txnStatus,isRoyalty,startTime,endTime);
    }

    @Override
    public List<UserOrderVO> getAllOrderList(List<Integer> userIdList,  Integer txnStatus,String isRoyalty,String startTime,String endTime) {
        return this.getBaseMapper().getAllOrderList(userIdList,txnStatus,isRoyalty,startTime,endTime);
    }

    @Override
    public int updateUserMoney(int userId, int money, int toalMoney) {
        return this.getBaseMapper().updateUserMoney(userId,money,toalMoney);
    }

    @Override
    @Transactional
    public boolean h5Registry(H5UserVO h5UserVO) {

        QueryWrapper<UserVipCardEntity> vipCardWrap = new QueryWrapper<UserVipCardEntity>();
        vipCardWrap.eq("card_code",h5UserVO.getCardCode());
        UserVipCardEntity userVipCardEntity = userVipCardService.getOne(vipCardWrap);
        if (userVipCardEntity == null){
            throw new BusinessException(ErrorType.BIZ_ERROR,"该会员卡不存在！");
        }
        if (userVipCardEntity.getCardStatus() == 1){
            throw new BusinessException(ErrorType.BIZ_ERROR,"该会员卡已被激活！");
        }
        if (!DateFullUtils.compareDate(new Date(),userVipCardEntity.getEffectiveTime())){
            throw new BusinessException(ErrorType.BIZ_ERROR,"该会员卡已过期！");
        }

        MemberCardEntity memberCardEntity =  memberCardService.getById(userVipCardEntity.getCardId());

        QueryWrapper<AppMemberEntity> userWrap = new QueryWrapper<AppMemberEntity>();
        userWrap.eq("phone",h5UserVO.getPhone());
        AppMemberEntity appMemberEntity =  appMemberService.getOne(userWrap);
        if (appMemberEntity == null){
            throw new BusinessException(ErrorType.BIZ_ERROR,"手机号码不存在！");
        }
        if (appMemberEntity.getMemberLevel() > memberCardEntity.getLevel()){
            throw new BusinessException(ErrorType.BIZ_ERROR,"当前用户会员等级比该分享的卡等级高，不可使用");
        }
        QueryWrapper<UserEntity> wrap = new QueryWrapper<UserEntity>();
        wrap.eq("phone",h5UserVO.getPhone());
        UserEntity findUser = this.getOne(wrap);
        int userId = 0;
        if (findUser == null){
            UserEntity  userEntity = new UserEntity();
            userEntity.setPid(userVipCardEntity.getUserId());
            userEntity.setAppUserId(appMemberEntity.getId());
            userEntity.setCreateTime(new Date());
            userEntity.setType(2);
            userEntity.setUserType("1");
            userEntity.setUsername(h5UserVO.getUserName());
            userEntity.setPhone(h5UserVO.getPhone());
            userEntity.setAddress(h5UserVO.getAddress());
            userEntity.setExigencyUserName(h5UserVO.getExigencyUserName());
            userEntity.setExigencyUserTel(h5UserVO.getExigencyUserTel());
            userEntity.setGender(h5UserVO.getGender());
            userEntity.setAge(h5UserVO.getAge());
            //头像
            if (!org.apache.commons.lang3.StringUtils.isBlank(appMemberEntity.getAvatar())){
                userEntity.setAvatarUrl(appMemberEntity.getAvatar());
            }else{
                userEntity.setAvatarUrl(requestUrl+"static/user/avatar.png");
            }
            this.getBaseMapper().insert(userEntity);
            userId = userEntity.getId();
        }else{
            userId = findUser.getId();
        }
        //更改用户的h会员有效期
        Date expireDate ;
        if (appMemberEntity.getMemberexpiredate() !=null){
            expireDate = DateFullUtils.addDate(appMemberEntity.getMemberexpiredate(),memberCardEntity.getValidityPeriod());
        }else{
            //当前会员等级比原有的要高，则是当前时间加有效期
            if (memberCardEntity.getLevel() > appMemberEntity.getMemberLevel() ){
                expireDate = DateFullUtils.addDate(new Date(),memberCardEntity.getValidityPeriod());
            }else{
           // 统计卡 当前有效期延长
                expireDate = DateFullUtils.addDate(appMemberEntity.getMemberexpiredate(),memberCardEntity.getValidityPeriod());
            }
        }
        //修改会员等级和有效期
        appMemberEntity.setMemberexpiredate(expireDate);
        appMemberEntity.setUpdatedate(new Date());
        appMemberEntity.setMemberLevel(memberCardEntity.getLevel());
        appMemberService.updateById(appMemberEntity);

        ChildUserVipCardEntity childUserVipCardEntity = new ChildUserVipCardEntity();
        childUserVipCardEntity.setCardId(userVipCardEntity.getId());
        childUserVipCardEntity.setUserId(userId);
        childUserVipCardEntity.setPUserId(userVipCardEntity.getUserId());
        childUserVipCardEntity.setCreateTime(new Date());
        childUserVipCardEntity.setEffectiveTime(expireDate);

        //插入用户拥有的卡
        childUserVipCardService.save(childUserVipCardEntity);

        //修改卡赠与的卡状态
        userVipCardEntity.setCardStatus(1);
        userVipCardEntity.setUpdateTime(new Date());
        boolean bl = userVipCardService.updateById(userVipCardEntity);
        return bl;
    }

    private String decrypt(String encryptedData, String iv, String sessionKey) throws Exception {

        byte[] dataBytes = Base64.decodeBase64(encryptedData);
        byte[] keyBytes = Base64.decodeBase64(sessionKey);
        byte[] ivBytes = Base64.decodeBase64(iv);

        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);
        byte[] finalData = cipher.doFinal(dataBytes);

        return new String(finalData);
    }
}
